#define _GNU_SOURCE

#include "app_device.h"
#include <fcntl.h>
#include <unistd.h>
#include "app_pool.h"
#include "app_mqtt.h"
#include "log/log.h"
#include "app_message.h"
#include <stdlib.h>
#include "app_common.h"

#define BUFFER_SIZE 1024
#define POOL_SIZE 5
#define WRITE_INTERVAL_MS 200

static Device *device = NULL; // 单例模式

Device *app_device_init(char *filename) {
    if (device) {
        return device;
    }
    device = (Device *)malloc(sizeof(Device));
    device->filename = filename;
    device->fd = open(filename, O_RDWR);
    device->up_buffer = app_buffer_init(BUFFER_SIZE);
    device->down_buffer = app_buffer_init(BUFFER_SIZE);
    device->is_running = 0;
    device->last_write_time = 0;
    device->post_read = NULL;
    device->pre_write = NULL;

    // 初始化相关模块
    app_pool_init(POOL_SIZE);
    app_mqtt_init();

    return device;
}

// 发送消息到远程的任务函数 =》由线程池中的某个线程调用处理
static int send_task_func(void *arg) {
    // 从上行缓冲区中读取一个字符数组消息
    char data_buf[128];
    int len = app_buffer_read(device->up_buffer, data_buf, sizeof(data_buf));
    // 将字符数组消息转换为json消息
    char *json = app_message_charsToJson(data_buf, len);
    // 发送消息到远程
    int result = app_mqtt_send(json);
    if (result == -1) {
        log_error("发送消息失败");
        return -1;
    }
    log_debug("发送消息成功：%s", json);
    return 0;
}

// 读数据的线程函数
static void *read_thread_func(void *arg) {
    while(device->is_running) {
        // 读文件数据
        char data_buf[128];
        int len = read(device->fd, data_buf, sizeof(data_buf));
        // log_debug("读取串口数据， 长度：%d", len);
        // 接收的蓝牙数据并不是一 次读取出来，而是要多次读取，且还有一些无用数据

        if (len > 0) {
            // 将读取的蓝牙数据转换为字符数组消息
            if (device->post_read) {
                len = device->post_read(data_buf, len);
                if (len > 0) {
                    app_buffer_write(device->up_buffer, data_buf, len);
                    // 将发送消息的任务交给线程池处理
                    app_pool_registerTask(send_task_func, NULL);
                }
            }

            
        }
    }
}

static long temp_time = 0;
int write_task_func(void *arg) {
    // 从下行缓冲区中读取一个字符数组消息
    char data_buf[128];
    int len = app_buffer_read(device->down_buffer, data_buf, sizeof(data_buf));
    // 将字符数组消息转换为设备文件数据（蓝牙）
    if (len>0  && device->pre_write) {
        len = device->pre_write(data_buf, len);

        // 写入设备文件
        if (len > 0) {
            // 写之前，需要保证与上次写入的时间间隔不小于WRITE_INTERVAL_MS
            long current_time = app_common_getCurrentTime();
            long interval = current_time - temp_time;
            
            if (interval < WRITE_INTERVAL_MS) {
                temp_time = current_time + (WRITE_INTERVAL_MS - interval);
                usleep((WRITE_INTERVAL_MS - interval) * 1000);
            } else { 
                temp_time = current_time; // 保存当前时间
            }

            
            int write_len = write(device->fd, data_buf, len);
            if (write_len!=len) {
                log_error("写入设备文件失败");
                return -1;
            }
            // 保存最后写入时间
            device->last_write_time = temp_time;

            log_debug("向下游设备发送数据成功：%s", app_common_charsToHexstr(data_buf, len));
            return 0;
        }
    }

    

    return -1;
    
}

// 接收处理远程消息的回调
int receive_msg_callback (char *json) {
   // 将json消息转换为字符数组消息
   char data_buf[128];
   int len = app_message_jsonToChars(json, data_buf, sizeof(data_buf)); 
   // 将字符数组消息缓存到下行缓冲区
   app_buffer_write(device->down_buffer, data_buf, len);
   // 将消息数据写入设备文件的任务交给线程池处理
   app_pool_registerTask(write_task_func, NULL);

}

int app_device_start(void)
{
    if (device->is_running) {
        log_debug("设备已启动运行中...");
        return 0;
    }
    device->is_running = 1;

    // 创建启动读数据线程
    pthread_create(&device->read_thread, NULL, read_thread_func, NULL);

    // 注册接收处理远程消息的回调
    app_mqtt_registerRecvCallback(receive_msg_callback);

    return 0;
}

int app_device_destroy(void)
{
    // 停止线程
    device->is_running = 0;
    pthread_cancel(device->read_thread);
    close(device->fd);
    app_buffer_free(device->down_buffer);
    app_buffer_free(device->up_buffer);
    device->post_read = NULL;
    device->pre_write = NULL;
    device->last_write_time = 0;

    app_mqtt_close();
    app_pool_close();


    return 0;
}
